package com.yanqu.road.server.manger.activity.gourdchild;

import com.yanqu.road.entity.activity.ActivityConfig;
import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.activity.gourdchild.GourdChildConfig;
import com.yanqu.road.entity.activity.gourdchild.Grid;
import com.yanqu.road.entity.activity.gourdchild.GridData;
import com.yanqu.road.entity.activity.gourdchild.config.GourdLevelInfo;
import com.yanqu.road.entity.activity.gourdchild.config.GourdLevelLotusInfo;
import com.yanqu.road.entity.activity.gourdchild.config.GourdMountainControl;
import com.yanqu.road.entity.activity.gourdchild.config.GourdMountainItem;
import com.yanqu.road.entity.activity.gourdchild.enums.eElementType;
import com.yanqu.road.entity.activity.gourdchild.enums.eGridObjectType;
import com.yanqu.road.entity.activity.gourdchild.enums.eMoveDirectionType;
import com.yanqu.road.entity.enums.eActivityConfigType;
import com.yanqu.road.entity.enums.eActivityType;
import com.yanqu.road.logic.bussiness.activity.GourdChildBussiness;
import com.yanqu.road.pb.activity.GourdChildProto;
import com.yanqu.road.server.TempMgr;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.activity.gourdchild.GourdChildModule;
import com.yanqu.road.server.manger.activity.NormalActivityMgr;
import com.yanqu.road.server.manger.player.GamePlayerMgr;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.utils.string.StringUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class GourdChildMgr extends TempMgr {

    public static int ACTIVITY_CHILD_TYPE = 1;

    private static GourdChildConfig config;

    private static int MAX_LEVEL = 8;

    /**
     * 格子数（4*4）
     */
    public static final int GRID_SIDE_LENGTH = 4;

    @Override
    public boolean init() throws Exception {
        return reload();
    }

    @Override
    public boolean reloadConfig() throws Exception {
        return true;
    }

    @Override
    public boolean reloadData() throws Exception {
        return true;
    }

    @Override
    public boolean stop() {
        return false;
    }

    public static ActivityInfo getActivityInfo() {
        return config == null ? null : config.getActivityInfo();
    }

    public static void reloadActivityData() {
        getLogger().info("reload GourdChild Activity start");

        ActivityInfo activityInfo;

        // 获取进行中的活动信息
        List<ActivityInfo> openActivityInfoList = NormalActivityMgr.getOpenActivityInfoList(eActivityType.GourdChildActivity.getValue(), ACTIVITY_CHILD_TYPE);
        if (openActivityInfoList.isEmpty()) {
            getLogger().info("no GourdChild Activity in show time");
            config = null;
            return;
        } else {
            activityInfo = openActivityInfoList.get(0);
        }

        GourdChildConfig tmpConfig = new GourdChildConfig();
        tmpConfig.setActivityInfo(activityInfo);
        int tmpActivityId = activityInfo.getActivityId();

        //初始化配置

        // 配置表配置
        tmpConfig.setBookInfoMap(GourdChildBussiness.getGourdChildLevelBookInfo(tmpActivityId));
        List<GourdLevelInfo> levelInfos = GourdChildBussiness.getGourdChildLevelInfo(tmpActivityId);
        Map<Integer, GourdLevelInfo> levelInfoMap = new ConcurrentHashMap<>();
        int size = levelInfos.size();
        for (int i = 0; i < size; i++) {
            GourdLevelInfo levelInfo = levelInfos.get(i);
            if(i == 0){
                tmpConfig.setStartLevel(levelInfo);
            }
            if(i == size - 1){
                tmpConfig.setLastLevel(levelInfo);
            }
            levelInfoMap.put(levelInfo.getId(), levelInfo);
            if(i + 1 < size){
                levelInfo.setNext(levelInfos.get(i + 1));
            }
        }
        tmpConfig.setLevelInfoMap(levelInfoMap);
        tmpConfig.setLevelInfoList(levelInfos);
        tmpConfig.setLotusInfoMap(GourdChildBussiness.getGourdChildLotusInfo(tmpActivityId));

        // config配置
        Map<String, ActivityConfig> activityConfigMap = NormalActivityMgr.getActivityConfigMap(tmpActivityId);
        tmpConfig.setScoreItemId(activityConfigMap.get(eActivityConfigType.GOURD_CHILD_SCORE_ITEM_ID.getName()).getIntValue());
        tmpConfig.setEnergyRecItemId(activityConfigMap.get(eActivityConfigType.GOURD_CHILD_ENERGY_ITEM_ID.getName()).getIntValue());
        // 体力参数
        List<Integer> energyParam = activityConfigMap.get(eActivityConfigType.GOURD_CHILD_ENERGY_PARAM.getName()).getIntListValue(";");
        tmpConfig.setMaxEnergy(energyParam.get(0));
        tmpConfig.setInitEnergy(energyParam.get(1));
        tmpConfig.setEnergyRecTime(energyParam.get(2));
        tmpConfig.setEnergyRecCount(energyParam.get(3));

        tmpConfig.setDefaultUnitNum(activityConfigMap.get(eActivityConfigType.GOURD_CHILD_DEFAULT_UNIT_NUM.getName()).getIntValue());

        //盲盒配置
        tmpConfig.setMountainConsume(activityConfigMap.get(eActivityConfigType.GOURD_CHILD_MOUNTAIN_CONSUME.getName()).getValue());
        tmpConfig.setMountainLuckyParam(StringUtils.stringToIntegerList(activityConfigMap.get(eActivityConfigType.GOURD_CHILD_MOUNTAIN_LUCKY_PARAM.getName()).getValue(), ";"));
        tmpConfig.setHideBoxCount(tmpConfig.getMountainLuckyParam().get(1) * activityInfo.getServerIdList().size());
        tmpConfig.setMountainAdditionParam(StringUtils.stringToIntegerList(activityConfigMap.get(eActivityConfigType.GOURD_CHILD_MOUNTAIN_ADDITION_PARAM.getName()).getValue(), ";"));

        String mountainItemParam = activityConfigMap.get(eActivityConfigType.GOURD_CHILD_MOUNTAIN_ITEM_PARAM.getName()).getValue();
        List<GourdMountainItem> itemList = new ArrayList<>();
        List<String> tempList = StringUtils.stringToStringList(mountainItemParam, "\\|");
        for (String s : tempList) {
            List<Integer> integers = StringUtils.stringToIntegerList(s, ";");
            GourdMountainItem item = new GourdMountainItem();
            item.setItemId(integers.get(0));
            item.setWeight(integers.get(1));
            item.setGrand(integers.get(2) == 1 ? true : false);
            itemList.add(item);
        }
        tmpConfig.setMountainItemList(itemList);

        String mountainRewardRepeatControl = activityConfigMap.get(eActivityConfigType.GOURD_CHILD_MOUNTAIN_REWARD_REPEAT_CONTROL.getName()).getValue();
        tempList = StringUtils.stringToStringList(mountainRewardRepeatControl, "\\|");
        List<GourdMountainControl> controlList = new ArrayList<>();
        for (String s : tempList) {
            List<Integer> integers = StringUtils.stringToIntegerList(s, ";");
            GourdMountainControl item = new GourdMountainControl();
            item.setDistinct(integers.get(0));
            item.setTimes(integers.get(1));
            controlList.add(item);
        }
        tmpConfig.setControlList(controlList);

        tmpConfig.setMountainNoticeCount(activityConfigMap.get(eActivityConfigType.GOURD_CHILD_MOUNTAIN_NOTICE_COUNT.getName()).getIntValue());
        Map<Integer, Integer> damageMap = new HashMap<>();
        String damageParam = activityConfigMap.get(eActivityConfigType.GOURD_CHILD_DAMAGE_PARAM.getName()).getValue();
        List<String> beiShu = StringUtils.stringToStringList(damageParam, "\\|");
        for (String s : beiShu) {
            List<Integer> bs = StringUtils.stringToIntegerList(s, ";");
            damageMap.put(bs.get(0), bs.get(1));
        }
        tmpConfig.setDamageParam(damageMap);

        config = tmpConfig;
        getLogger().info("reload GourdChild Activity finish");

        // 在线玩家下发数据
        for (GamePlayer gamePlayer : GamePlayerMgr.getAllOnlinePlayer()) {
            GourdChildModule module = gamePlayer.getModule(GourdChildModule.class);
            module.syncConfig();
            module.initUserData();
            module.syncUserData();
            module.syncGameData();
        }
    }

    /**
     * 星级
     */
    public static int getPassStar(int round, List<Integer> starLimit) {
        int start = 0;
        for (int i = 0; i < starLimit.size(); i++) {
            if(round <= starLimit.get(i)){
                start++;
            }
        }
        return start;
    }

    /**
     * 移动一步
     */
    public static MoveMergerResult move(List<Grid> gridList, eMoveDirectionType directionType){
        List<Grid> copyGridList = copyGridList(gridList);
        MoveMergerResult moveMergerResult = new MoveMergerResult();
        //起始边界（墙）
        int[] startIndex = getBoundaryIndex(GRID_SIDE_LENGTH, directionType);
        //边界后置与前置的间隔
        int gap = getPerGridGap(GRID_SIDE_LENGTH, directionType);
        //对立边界
        int[] endIndex = new int[GRID_SIDE_LENGTH];
        for (int k = 0; k < startIndex.length; k++) {
            int index = startIndex[k];
            //从每行或者列的第二个位置开始比较
            for(int i = 1; i < GRID_SIDE_LENGTH; i++){
                int currIndex = index + i * gap;
                //记录另一头边界
                endIndex[k] = currIndex;
                int frontIndex = getFrontPositionIndex(GRID_SIDE_LENGTH, directionType, currIndex);
                if(currIndex < 0 || frontIndex < 0 || currIndex >= copyGridList.size() || frontIndex >= copyGridList.size()){
                    //算法错误
                    moveMergerResult.setRet(GameErrorCode.E_GOURD_CHILD_ACTIVITY_MOVE_STEP_ERROR);
                    return moveMergerResult;
                }
                Grid curr = copyGridList.get(currIndex);
                Grid front = copyGridList.get(frontIndex);
                //合并格子
                Grid newGrid = mergeGrid(curr, front);
                if(newGrid == null){
                    continue;
                }
                //记录移动过的格子
                moveMergerResult.getMovedIndexList().add(currIndex);
                //是否触发攻击
                if(triggerAttack(newGrid)){
                    //清除攻击格子及记录结果
                    copyGridList.set(frontIndex, new Grid());
                    moveMergerResult.getAttackList().add(newGrid);
                }else {
                    //设置新格子
                    copyGridList.set(frontIndex, newGrid);
                }
                //清除当前格子
                copyGridList.set(currIndex, new Grid());
                //本次移动格子数+1
                moveMergerResult.setStep(1 + moveMergerResult.getStep());
            }
        }
        if(moveMergerResult.getStep() == 0){
            //不可移动
            moveMergerResult.setRet(GameErrorCode.E_GOURD_CHILD_ACTIVITY_NO_GRID_TO_MERGE);
        }else {
            //生成新格子
            List<Integer> randomIndex = new ArrayList<>();
            for (int i : endIndex) {
                //对立列是否都是空格子
                if(copyGridList.get(i).getData().size() == 0){
                    randomIndex.add(i);
                }
            }
            if(randomIndex.size() == 0){

            }else {
                //有空格子，记录下标
                Random random = new Random();
                int idx = random.nextInt(randomIndex.size());
                moveMergerResult.setNewIndex(randomIndex.remove(idx));
                //在外部设置新格子的数据
            }
        }
        moveMergerResult.setResultList(copyGridList);
        return moveMergerResult;
    }

    /**
     * 合并格子
     * 没有合并的时候返回null
     */
    public static Grid mergeGrid(Grid curr, Grid front){
        //前置是墙壁，无法移动
        if(front == null){
            return null;
        }
        //我是空白位置，无需移动
        if(curr.getData().size() == 0){
            return null;
        }
        //前置空白位置，直接移动
        if(front.getData().size() == 0){
            return curr.clone();
        }
        int eType1 = getElementType(curr);
        int eType2 = getElementType(front);
        //基本元素不同，则不可合并
        if(eType1 != 0 && eType2 != 0 && eType1 != eType2){
            return null;
        }
        //元素在没有葫芦的情况不可与葫芦娃合并
        if(eType1 != 0 && !containsOType(curr, eGridObjectType.GOURD.getType()) && containsOType(front, eGridObjectType.GOURD_CHILD.getType())){
            return null;
        }
        if(eType2 != 0 && !containsOType(front, eGridObjectType.GOURD.getType()) && containsOType(curr, eGridObjectType.GOURD_CHILD.getType())){
            return null;
        }
        //葫芦与葫芦娃的等级要相同
//        GridData currGridData = getGridDataByOType(curr, eGridObjectType.GOURD.getSchoolType());
//        GridData fontGridData = getGridDataByOType(front, eGridObjectType.GOURD_CHILD.getSchoolType());
//        if(currGridData != null && fontGridData != null && (currGridData.getLv() != fontGridData.getLv())){
//            return null;
//        }
//        currGridData = getGridDataByOType(curr, eGridObjectType.GOURD_CHILD.getSchoolType());
//        fontGridData = getGridDataByOType(front, eGridObjectType.GOURD.getSchoolType());
//        if(currGridData != null && fontGridData != null && (currGridData.getLv() != fontGridData.getLv())){
//            return null;
//        }
        //合并成新格子数据
        Grid newGrid = new Grid();
        for (GridData datum : curr.getData()) {
            newGrid.getData().add(datum.clone());
        }
        for (GridData datum : front.getData()) {
            mergeGridData(newGrid, datum);
        }
        return newGrid;
    }

    /**
     * 格子是否触发攻击
     */
    public static boolean triggerAttack(Grid grid){
        if(grid == null){
            return false;
        }
        //有葫芦且有葫芦娃
        if(containsOType(grid, eGridObjectType.GOURD.getType()) && containsOType(grid, eGridObjectType.GOURD_CHILD.getType())){
            return true;
        }
        return false;
    }

    /**
     * 获取基本元素的类型
     * 无则返回0
     */
    public static int getElementType(Grid grid){
        for (GridData datum : grid.getData()) {
            if(datum.getEt() == eElementType.ELEMENT.getType()){
                return datum.getOt();
            }
        }
        return 0;
    }

    /**
     * 创建一个格子数据
     */
    public static GridData newGridData(int type, int level){
        GridData data = new GridData();
        data.setOt(type);
        data.setLv(level);
        if(type < eGridObjectType.GOURD.getType()){
            data.setEt(eElementType.ELEMENT.getType());
        }else {
            data.setEt(eElementType.NO_ELEMENT.getType());
        }
        return data;
    }

    /**
     * 随机一个格子数据
     */
    public static GridData randomGridData(List<Integer> elementList){
        List<Integer> typeList = new ArrayList<>(elementList);
        Random random = new Random();
        int typeIdx = random.nextInt(typeList.size());
        GridData gridData = newGridData(typeList.get(typeIdx), 1);
        return gridData;
    }

    /**
     * 构建可选的元素
     */
    public static List<Integer> buildSelectList(List<Integer> elementList) {
        List<Integer> typeList = new ArrayList<>();
        for (int ele : elementList) {
            typeList.add(ele);
        }
        typeList.add(eGridObjectType.GOURD.getType());
        typeList.add(eGridObjectType.GOURD_CHILD.getType());
        return typeList;
    }

    /**
     * 初始化格子单元
     */
    public static List<Grid> initGrid(int sideLength, int num, List<Integer> elementList){
        List<Grid> list = new ArrayList<>();
        List<Integer> indexList = new ArrayList<>();
        int all = sideLength * sideLength;
        if(num > all){
            return list;
        }
        for(int i = 0; i < all; i++){
            list.add(new Grid());
            indexList.add(i);
        }
        List<Integer> typeList = buildSelectList(elementList);
        Random random = new Random();
        for(int i = 0; i < num; i++){
            int gridIdx = random.nextInt(indexList.size());
            int typeIdx = random.nextInt(typeList.size());
            GridData gridData = newGridData(typeList.get(typeIdx), 1);
            int grid = indexList.remove(gridIdx);
            list.get(grid).getData().add(gridData);
            //getLogger().debug("--grid {}", grid);
        }
        return list;
    }

    /**
     * 是否包含某个类型
     */
    public static boolean containsOType(Grid grid, int oType){
        for (GridData datum : grid.getData()) {
            if(datum.getOt() == oType){
                return true;
            }
        }
        return false;
    }

    /**
     * 获取格子数据
     */
    public static GridData getGridDataByOType(Grid grid, int oType){
        for (GridData datum : grid.getData()) {
            if(datum.getOt() == oType){
                return datum;
            }
        }
        return null;
    }

    /**
     * 合并格子数据
     */
    public static void mergeGridData(Grid newGrid, GridData gridData){
        GridData old = getGridDataByOType(newGrid, gridData.getOt());
        if(old == null){
            newGrid.getData().add(gridData.clone());
        }else {
            old.setLv(old.getLv() + gridData.getLv());
            if(old.getLv() > MAX_LEVEL){
                old.setLv(MAX_LEVEL);
            }
        }
    }

    /**
     * 复制格子数据
     */
    public static List<Grid> copyGridList(List<Grid> sourceList){
        List<Grid> resultList = new ArrayList<>();
        for (Grid grid : sourceList) {
            resultList.add(grid.clone());
        }
        return resultList;
    }

    /**
     * 随机n个基础元素
     */
    public static List<Integer> randomElementType(int num){
        List<Integer> selectList = new ArrayList<>();
        for (eGridObjectType type : eGridObjectType.values()) {
            if(type.getType() < eGridObjectType.GOURD.getType()){
                selectList.add(type.getType());
            }
        }
        List<Integer> result = new ArrayList<>();
        Random random = new Random();
        while (num > 0 && selectList.size() > 0) {
            int idx = random.nextInt(selectList.size());
            int type = selectList.remove(idx);
            result.add(type);
            num--;
        }
        return result;
    }

    /**
     * 获取移动方向上的边界（起始不能动的位置）
     */
    public static int[] getBoundaryIndex(int sideLength, eMoveDirectionType directionType){
        int[] boundaryIndex = new int[sideLength];
        int start;
        switch (directionType){
            case UP:
                start = sideLength * (sideLength - 1);
                for(int i = 0; i < sideLength; i++){
                    boundaryIndex[i] = start + i;
                }
                break;
            case RIGHT:
                start = sideLength - 1;
                for(int i = 0; i < sideLength; i++){
                    boundaryIndex[i] = start + i * sideLength;
                }
                break;
            case DOWN:
                start = 0;
                for(int i = 0; i < sideLength; i++){
                    boundaryIndex[i] = start + i;
                }
                break;
            case LEFT:
                start = 0;
                for(int i = 0; i < sideLength; i++){
                    boundaryIndex[i] = start + i * sideLength;
                }
                break;
        }
        return boundaryIndex;
    }

    /**
     * 获取当前移动方向上的前置位置
     */
    public static int getFrontPositionIndex(int sideLength, eMoveDirectionType directionType, int curIndex){
        int index = -1;
        switch (directionType){
            case UP:
                index = curIndex + sideLength;
                break;
            case RIGHT:
                index = curIndex + 1;
                break;
            case DOWN:
                index = curIndex - sideLength;
                break;
            case LEFT:
                index = curIndex - 1;
                break;
        }
        return index;
    }

    /**
     *  获取当前移动方向上的间隔
     */
    public static int getPerGridGap(int sideLength, eMoveDirectionType directionType){
        int gap = 0;
        switch (directionType){
            case UP:
                gap = -sideLength;
                break;
            case RIGHT:
                gap = -1;
                break;
            case DOWN:
                gap = sideLength;
                break;
            case LEFT:
                gap = 1;
                break;
        }
        return gap;
    }

    /**
     * 补充下一步移动的提示数据
     */
    public static void appendMovableData(GourdChildProto.GourdChildGameDataMsg.Builder gameData, List<Grid> gridList, GourdChildConfig childConfig) {
        int emptySize = 0;
        for (Grid grid : gridList) {
            if(grid.getData().size() == 0){
                emptySize++;
            }
        }
        if(emptySize == gridList.size()){
            return;
        }
        for (eMoveDirectionType directionType : eMoveDirectionType.values()) {
            MoveMergerResult result = GourdChildMgr.move(gridList, directionType);
            if(result.getMovedIndexList().size() > 0){
                int damage = getDamage(result, childConfig, gameData.getLotusLv());
                GourdChildProto.GourdChildMovableGridTemp.Builder step = GourdChildProto.GourdChildMovableGridTemp.newBuilder();
                step.setDirection(directionType.getType());
                step.setDamage(damage);
                for (int idx : result.getMovedIndexList()) {
                    step.addIdx(idx);
                }
                gameData.addNextMove(step);
            }
        }
    }

    /**
     * 获取攻击伤害
     */
    public static int getDamage(MoveMergerResult moveMergerResult, GourdChildConfig config, int lotusLv) {
        int size  = moveMergerResult.getAttackList().size();
        int totalDamage = 0;
        if(size > 0) {
            //伤害=基础伤害* 葫芦娃等级*（元素等级+葫芦等级）
            GourdLevelLotusInfo lotusInfo = config.getLotusInfoMap().get(lotusLv);
            for (Grid grid : moveMergerResult.getAttackList()) {
                int elv = 0;
                int gourdLv = 1;
                int gourdChildLv = 1;
                for (GridData gridData : grid.getData()) {
                    if(gridData.getEt() == eElementType.ELEMENT.getType()){
                        elv = gridData.getLv();
                    }else if(gridData.getOt() == eGridObjectType.GOURD.getType()){
                        gourdLv = gridData.getLv();
                    }else if(gridData.getOt() == eGridObjectType.GOURD_CHILD.getType()){
                        gourdChildLv = gridData.getLv();
                    }
                }
                int damage = (lotusInfo.getDamage() * gourdChildLv * (elv + gourdLv));
                //加成
                damage = additionCal(damage, config, size);
                moveMergerResult.getAttackDamage().add(Long.valueOf(damage));
                totalDamage += damage;
            }
            //getLogger().debug("grid : {}, totalDamage {}", JSON.toJSONString(moveMergerResult.getAttackList()), JSON.toJSONString(moveMergerResult.getAttackDamage()));
        }
        return totalDamage;
    }

    /**
     * 伤害加成
     */
    private static int additionCal(int totalDamage, GourdChildConfig config, int size) {
        int addition = 1000;
        if(config.getDamageParam().containsKey(size)){
            addition = config.getDamageParam().get(size);
        }
        return BigDecimal.valueOf(totalDamage).multiply(BigDecimal.valueOf(addition)).divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP).intValue();
    }

    //--------get/set
    public static GourdChildConfig getConfig() {
        return config;
    }

}
